package com.hospital.register.core.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hospital.register.common.exception.BusinessException;
import com.hospital.register.common.result.ResultCodeEnum;
import com.hospital.register.common.utils.MD5;
import com.hospital.register.core.mapper.HospitalSetMapper;
import com.hospital.register.core.service.HospitalSetService;
import com.hospital.register.dto.core.admin.HospitalSetQueryDto;
import com.hospital.register.constants.HospitalSetConstants;
import com.hospital.register.model.core.HospitalSet;
import com.hospital.register.vo.core.admin.HospitalSetPageVo;
import com.hospital.register.vo.core.api.HospitalSignVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

@Service
public class HospitalSetServiceImpl implements HospitalSetService {

    /**
     * 访问医院设置
     */
    @Autowired
    private HospitalSetMapper hospitalSetMapper;

    @Override
    @Transactional(readOnly = true, timeout = 5)
    public List<HospitalSet> selectAll() {
        return this.hospitalSetMapper.selectAll();
    }

    @Override
    @Transactional(timeout = 5)
    public boolean deleteById(Long id) {
        return this.hospitalSetMapper.deleteById(id, new Date()) == 1;
    }

    @Override
    @Transactional(timeout = 5, readOnly = true)
    public Page<HospitalSetPageVo> selectPage(Page<HospitalSetPageVo> page, HospitalSetQueryDto conditions) {
        return this.hospitalSetMapper.selectPage(page, conditions);
    }

    @Override
    @Transactional(timeout = 5)
    public boolean insert(HospitalSet hospitalSet) {
        hospitalSet.setStatus(HospitalSetConstants.STATUS_ENABLED);//状态 启用
        //设置签名（随机字符串）
        hospitalSet.setSignKey(MD5.encrypt(System.currentTimeMillis() + "" + ThreadLocalRandom.current().nextInt(1000)));
        return this.hospitalSetMapper.insert(hospitalSet) == 1;
    }

    @Override
    @Transactional(readOnly = true, timeout = 5)
    public HospitalSet selectById(Long id) {
        return this.hospitalSetMapper.selectById(id);
    }

    @Override
    @Transactional(timeout = 5)
    public boolean updateById(HospitalSet hospitalSet) {
        return this.hospitalSetMapper.updateById(hospitalSet) == 1;
    }

    @Override
    @Transactional(timeout = 5)
    public boolean deleteByIdList(List<Long> idList) {
        return this.hospitalSetMapper.deleteByIdList(idList, new Date()) == idList.size();
    }

    @Override
    @Transactional(timeout = 5)
    public boolean updateStatusById(Long id, Byte status) {
        return this.hospitalSetMapper.updateStatusById(id, status, new Date()) == 1;
    }

    @Override
    public String selectSignKeyByCode(String hoscode) {
        return this.hospitalSetMapper.selectSignKeyByCode(hoscode);
    }

    @Override
    public void checkSignKey(String hoscode, String sign, HttpServletRequest request) throws BusinessException {
        final String KEY_SIGN = "sign";//签名秘钥的参数名
        final String KEY_LOGODATA = "logoData";//logo 的参数名

        //根据医院编号获取签名
        String rightSign = this.hospitalSetMapper.selectSignKeyByCode(hoscode);
        if (rightSign == null || rightSign.equals("")) {
            throw new BusinessException("抱歉，验签失败，医院未接入", ResultCodeEnum.SIGN_ERROR.getCode());
        }

        //给数据库中的签名加盐，并使用 MD5 再次加密
        //首先对参数排序
        Enumeration<String> paramNames = request.getParameterNames();
        TreeMap<String, String> paramMap = new TreeMap<>();

        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            paramMap.put(paramName, request.getParameter(paramName));
        }

        //将所有参数值拼接到一个文本串中
        if (paramMap.containsKey(KEY_SIGN)) {
            paramMap.remove(KEY_SIGN);
        }

        if (paramMap.containsKey(KEY_LOGODATA)) {
            paramMap.put(KEY_LOGODATA, paramMap.get(KEY_LOGODATA).replaceAll(" ", "+"));//将logo中的空格替换为加号
        }

        StringBuilder paramValues = new StringBuilder();
        for (Map.Entry<String, String> oneParam : paramMap.entrySet()) {
            paramValues.append(oneParam.getValue()).append("|");
        }
        paramValues.append(rightSign);

        rightSign = MD5.encrypt(paramValues.toString());
        if (!rightSign.equals(sign)) {
            throw new BusinessException("抱歉，验签失败，签名错误。注意，如果项目是通过 cmd 运行的，发出的请求本身就会存在乱码。", ResultCodeEnum.SIGN_ERROR.getCode());
        }
    }

    @Override
    public HospitalSignVo selectSignByCode(String hoscode) {
        return this.hospitalSetMapper.selectSignByCode(hoscode);
    }

    //测试代码
//    由于验签总是失败，所以需要将生成签名的元数据写入到文件，方便测试类比较
    private void writeToFile(String text1, String text2) {
        BufferedWriter writer1 = null;
        BufferedWriter writer2 = null;
        try {
            writer1 = new BufferedWriter(new FileWriter("D:/abc/1.txt"));
            writer2 = new BufferedWriter(new FileWriter("D:/abc/2.txt"));

            writer1.write(text1);
            writer2.write(text2);

            writer1.flush();
            writer2.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                writer1.close();
                writer2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
